#pragma once

#include <memory>
#include <utility>

namespace zenox {

template <class T, class BaseAlloc = std::allocator<T>>
struct uninitialized_allocator : BaseAlloc {
    using value_type = T;

    uninitialized_allocator() = default;

    template <class ...Args>
    constexpr decltype(auto) allocate(Args &&...args) { // 分配与释放功能保持不变，我们只需要劫持构造功能的逻辑
        return BaseAlloc::allocate(std::forward<Args>(args)...);
    }

    template <class ...Args>
    constexpr decltype(auto) deallocate(Args &&...args) { // 全部给我完美转发过去
        return BaseAlloc::deallocate(std::forward<Args>(args)...);
    }

    template <class ...Args>
    constexpr void construct(T *p, Args &&...args) {
        if constexpr (!(sizeof...(Args) == 0 && std::is_trivially_default_constructible_v<T>)) // 如果是无参构造且类型为POD类型，则不0初始化
            ::new((void *)p) T(std::forward<Args>(args)...);       // 这样的话你仍然可以用 resize(n, 0) 来强制0初始化
    }

    template <class U, class OtherAlloc> // 下面这两个函数是为了伺候 MSVC 编译通过
    constexpr uninitialized_allocator(uninitialized_allocator<U, OtherAlloc> const &other) noexcept
    : BaseAlloc(static_cast<OtherAlloc const &>(other)) {}

    constexpr bool operator==(uninitialized_allocator const &other) const noexcept {
        return this == &other;
    }
};

/* template <class T> */ // deprecated, use pod_uninitialized in raiiutils.hpp instead
/* struct noinit { */
/*     T value; */
/*     constexpr noinit() {}  // 不是 = default，也不写 : value()，这样一来只要 T 是 POD 类型，value 就不会0初始化 */
/*     constexpr noinit(T value_) : value(std::move(value_)) {}  // 强制初始化的版本（T隐式转换为Noinit<T>） */
/*     constexpr operator T const &() const & { return value; } // Noinit<T>隐式转换为T */
/*     constexpr operator T &() & { return value; } */
/*     constexpr operator T const &&() const && { return std::move(value); } */
/*     constexpr operator T &&() && { return std::move(value); } */
/* }; */

}
